<?php

namespace apiend\models\forms;

use Yii;
use common\helpers\Utils;
use apiend\models\User;

/**
 * 短信验证码发送模型
 * 
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class SmsCaptchaForm extends \common\base\Model {

    use \common\traits\Constants;

    /**
     * 短信模板
     */
    const TPL_AUTH_CODE = 'SMS_134245055';

    /**
     * 登录短信
     */
    const SCOPE_LOGIN = 'login';

    /**
     * 忘记密码短信
     */
    const SCOPE_FORGET = 'forget';

    /**
     * 注册短信
     */
    const SCOPE_REGISTER = 'register';

    /**
     * 绑定手机号短信
     */
    const SCOPE_BIND = 'bind';

    /**
     * 发送次数限制数
     */
    const LIMIT_SEND_TIMES = 500;

    /**
     * 受限发送自动过期时间
     */
    const AUTO_FLUSH_DURATION = 86400;

    /**
     * 验证码过期时间
     */
    const CAPTCHA_EXPIRE_TIME = 600;

    /**
     * 发送倒计时
     */
    const SEND_PERIOD_TIME = 60;

    /**
     * @var string 允许发送的短信验证码类型范围
     */
    public $scope;

    /**
     * @var string 手机号
     */
    public $mobile;

    /**
     * @var integer 发送次数
     */
    private $_sendtimes = 0;

    /**
     * @var User 用户信息
     */
    private $_user = null;

    /**
     * @inheritdoc
     */
    public function rules() {
        return [
            [['mobile', 'scope'], 'required'],
            ['scope', 'in', 'range' => static::getAttributeMark('scope'), 'message' => '{attribute}不在允许的范围内'],
            ['mobile', '\common\validators\MobileValidator'],
            ['scope', 'validateSendscope'],
            ['mobile', 'validateSendRateLimit'],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels() {
        return [
            'mobile' => '手机号',
            'scope' => '标识范围',
        ];
    }

    /**
     * 校验发送范围是否允许
     * @param string $attribute the attribute currently being validated
     */
    public function validateSendscope($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        $user = $this->getUser();
        if ($user && in_array($this->$attribute, [self::SCOPE_REGISTER, self::SCOPE_BIND])) {
            $this->addError($attribute, '当前手机号已被占用');
        } elseif (!$user && in_array($this->$attribute, [self::SCOPE_LOGIN, self::SCOPE_FORGET])) {
            $this->addError($attribute, '当前手机号未注册帐号');
        }
    }

    /**
     * 校验发送短信是否受限
     * @param string $attribute the attribute currently being validated
     */
    public function validateSendRateLimit($attribute) {
        if (!$this->hasErrors()) {
            if ($this->sendTimes >= static::LIMIT_SEND_TIMES) {
                $this->addError($attribute, '超过了短信发送的限制次数，24小时之内将屏蔽当前手机号的短信发送。');
            }
            $period = Yii::$app->cache->get('period_' . $this->scope . '_' . $this->mobile);
            if ($period) {
                $waitsecond = $period + static::SEND_PERIOD_TIME - time();
                if ($waitsecond > 0) {
                    $this->addError($attribute, '重发倒计时剩余：' . $waitsecond . '秒');
                }
            }
        }
    }

    /**
     * 获取短信发送次数
     */
    public function getSendTimes() {
        $sendtimes = Yii::$app->cache->get('sendtimes_' . $this->scope . '_' . $this->mobile);
        if ($sendtimes) {
            $this->_sendtimes = $sendtimes;
        }
        return $this->_sendtimes;
    }

    /**
     * 生成短信校验码
     * @return string
     */
    protected function generateCaptcha() {
        $length = 6;
        $captcha = !YII_DEBUG ? Utils::random($length, true) : str_pad('8', $length, '8');
        Yii::$app->cache->set('captcha_' . $this->scope . '_' . $this->mobile, $captcha, static::CAPTCHA_EXPIRE_TIME);
        return $captcha;
    }

    /**
     * 获取用户信息
     * @return UserMeta|null
     */
    protected function getUser() {
        if ($this->_user === null) {
            $this->_user = User::findByMobile($this->mobile);
        }
        return $this->_user;
    }

    /**
     * 发送短信校验码
     * @return array
     */
    public function send() {
        if (!$this->validate()) {
            $this->dumpError('内容验证失败');
        }

        $token = null;
        if ($this->scope == self::SCOPE_FORGET) {
            $user = $this->getUser();
            $user->generatePasswordResetToken();
            if (!$user->save()) {
                return $user->dumpError('帐号异常，密码找回时发生了未知错误，请联系管理员或者使用其他方式找回', false);
            }
            $token = $user->password_reset_token;
        }

        $captcha = $this->generateCaptcha();
        //提交短信发送
        $status = Yii::$app->dysms->sendSms($this->mobile, static::TPL_AUTH_CODE, [
            'code' => $captcha,
        ]);
        if ($status !== true) {
            $this->saveError($status, false);
        }

        Yii::$app->cache->set('period_' . $this->scope . '_' . $this->mobile, time(), static::SEND_PERIOD_TIME);
        Yii::$app->cache->set('sendtimes_' . $this->scope . '_' . $this->mobile, $this->_sendtimes + 1, static::AUTO_FLUSH_DURATION);

        $data = [
            'status' => true,
            'message' => '发送成功',
            'times' => $this->_sendtimes + 1,
        ];
        if (YII_DEBUG) {
            $data['_debug'] = [
                'captcha' => $captcha,
            ];
        }
        if ($token !== null) {
            $data['reset_token'] = $token;
        }
        return $data;
    }

}
